/*
 *  Copyright 2016 http://www.kedacomframework.org
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

package com.kedacom.ctsp.authority.controller;

import com.kedacom.ctsp.authority.constant.AccessLoggerConstant;
import com.kedacom.ctsp.authority.constant.AuthorizeConstant;
import com.kedacom.ctsp.authority.entity.Department;
import com.kedacom.ctsp.authority.entity.DepartmentForTree;
import com.kedacom.ctsp.authority.service.DepartmentForTreeService;
import com.kedacom.ctsp.authority.service.DepartmentService;
import com.kedacom.ctsp.authority.vo.AuthorityImportExcelResultVo;
import com.kedacom.ctsp.authority.vo.DepartmentVO;
import com.kedacom.ctsp.authz.Authorize;
import com.kedacom.ctsp.lang.mapper.BeanMapper;
import com.kedacom.ctsp.logging.AccessLogger;
import com.kedacom.ctsp.web.controller.AbstractCrudTreeController2;
import com.kedacom.ctsp.web.controller.message.ResponseMessage;
import com.kedacom.ctsp.web.controller.util.QueryParamUtil;
import com.kedacom.ctsp.web.entity.TreeSupportBean;
import com.kedacom.ctsp.web.entity.page.PagerResult;
import com.kedacom.ctsp.web.entity.param.QueryParamEntity;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.kedacom.ctsp.web.controller.message.ResponseMessage.ok;

/**
 * 部门
 *
 * @author xuwei
 * @update 3.0.3 replace /matching with QueryController.list
 * @update 3.0.3 replace //parent/{deptId} /tree; /tree/{id};/parent/{deptId} with TreeController
 * @update 3.0.3 replace /unique/name;/unique/name with ImplictCrudController.checkUnique
 */
@RequestMapping("department")
@ResponseBody
@AccessLogger(AccessLoggerConstant.Module.DEPARTMENT)
@Authorize(resources = AuthorizeConstant.AUTH_DEPARTMENT)
@Api(tags = "DEPARTMENT", description = "部门管理")
@Slf4j
public class AuthorityDepartmentController extends AbstractCrudTreeController2<Department, String, DepartmentVO, DepartmentService> {

    @Autowired
    private DepartmentService departmentService;


    @Autowired
    private DepartmentForTreeService departmentForTreeService;

    @PostMapping("import")
    @ApiOperation("部门导入")
    public ResponseMessage<AuthorityImportExcelResultVo> importExcel(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws Exception {
        return ResponseMessage.ok(getService().importDepartment(file, request));
    }

    @Override
    @Authorize(resources = AuthorizeConstant.AUTH_DEPARTMENT_UPDATE)
    public ResponseMessage<String> updateByPrimaryKey(@PathVariable String id, @RequestBody DepartmentVO data) {
        return super.patchByPrimaryKey(id, data);
    }

    @Authorize(resources = AuthorizeConstant.AUTH_DEPARTMENT_QUERY)
    @Override
    public ResponseMessage<PagerResult<DepartmentVO>> list(QueryParamEntity param, HttpServletRequest request) {
        return super.list(param, request);
    }

    @Authorize(resources = AuthorizeConstant.AUTH_DEPARTMENT_QUERY)
    @Override
    public ResponseMessage<DepartmentVO> getByPrimaryKey(@PathVariable String id) {
        return super.getByPrimaryKey(id);
    }

    @Authorize(resources = AuthorizeConstant.AUTH_DEPARTMENT_ADD)
    @Override
    public ResponseMessage<String> add(@RequestBody DepartmentVO data) {
        return super.add(data);
    }

    @Authorize(resources = AuthorizeConstant.AUTH_DEPARTMENT_QUERY)
    @Override
    public ResponseMessage<List<DepartmentVO>> listAsTree(QueryParamEntity param, HttpServletRequest request) {
        QueryParamUtil.paddingTerms(param, request);
        param.setPaging(false);
        List<DepartmentForTree> nodes = departmentForTreeService.select(param);

        List<DepartmentVO> nodesForTree = nodesForTree(nodes);

        ResponseMessage<List<DepartmentVO>> result = ok(nodesForTree);
        result.exclude(TreeSupportBean.class, TreeSupportBean.PARENT);
        return result;
    }


    /**
     * 展示部门树状图，专用（DepartmentForTree 弃用hibernate 自动关联parent 上级部门），提高加载效率
     *
     * @param deptNodes
     * @return
     */
    private List<DepartmentVO> nodesForTree(List<DepartmentForTree> deptNodes) {

        //<id,DepartmentForTree>
        Map<String, DepartmentForTree> deptEntityMapById = new HashMap<>();
        List<DepartmentVO> deptVOLists = new ArrayList<>();

        //将entity转成VO
        deptNodes.stream().forEach(department -> {
            deptVOLists.add(BeanMapper.deepMap(department, DepartmentVO.class));
            deptEntityMapById.put(department.getId(), department);

        });

        //发给前端展示的部门树状列表
        List<DepartmentVO> deptVOTreeList = new ArrayList<>();

        //根据id关联部门VO
        Map<String, DepartmentVO> deptVOMapById = new HashMap<>();
        for (DepartmentVO departmentForTree : deptVOLists) {
            deptVOMapById.put(departmentForTree.getId(), departmentForTree);
        }

        //使用VO构建前端展示部门树列表
        for (DepartmentForTree departmentForTree : deptNodes) {

            String deptId = departmentForTree.getId();//部门id
            String parentId = departmentForTree.getParent_id();//部门上级id

            if (StringUtils.isBlank(parentId)) {
                //记录没有parentId的根节点
                deptVOTreeList.add(deptVOMapById.get(deptId));
                continue;
            }

            //获取上级部门VO
            DepartmentVO departmentParentVO = deptVOMapById.get(parentId);
            if (departmentParentVO == null) {
                continue;
            }

            //构建树状结构，child列表
            List<DepartmentVO> childVos = departmentParentVO.getChildren();
            if (childVos == null) {
                childVos = new ArrayList<>();
                departmentParentVO.setChildren(childVos);
            }
            childVos.add(deptVOMapById.get(deptId));
        }
        return deptVOTreeList;
    }


    @Authorize(resources = AuthorizeConstant.AUTH_DEPARTMENT_QUERY)
    @Override
    public ResponseMessage<List<DepartmentVO>> listAsTree(@PathVariable String id, QueryParamEntity param, HttpServletRequest request) {

        QueryParamUtil.paddingTerms(param, request);
        param.setPaging(false);
        List<DepartmentForTree> nodes = departmentForTreeService.selectAllChildNode(id, param);
        DepartmentForTree parentDept = departmentForTreeService.get(id);
        if (null != parentDept) {
            parentDept.setParent_id("");
            nodes.add(parentDept);
        }
        List<DepartmentVO> nodesForTree = nodesForTree(nodes);

        ResponseMessage<List<DepartmentVO>> result = ok(nodesForTree);
        result.exclude(TreeSupportBean.class, TreeSupportBean.PARENT);
        return result;

    }

    @Authorize(resources = AuthorizeConstant.AUTH_DEPARTMENT_QUERY)
    @Override
    public ResponseMessage<DepartmentVO> traceToTop(@PathVariable String id, QueryParamEntity param, HttpServletRequest request) {
        return super.traceToTop(id, param, request);
    }

    @Authorize(resources = AuthorizeConstant.AUTH_DEPARTMENT_QUERY)
    @Override
    public ResponseMessage<PagerResult<DepartmentVO>> listAllChildren(@PathVariable String id, QueryParamEntity param, HttpServletRequest request) {
        return super.listAllChildren(id, param, request);
    }

    @Authorize(resources = AuthorizeConstant.AUTH_DEPARTMENT_QUERY)
    @GetMapping("/getDept/{code}")
    public ResponseMessage<Department> getDeptByCode(@PathVariable String code, QueryParamEntity param, HttpServletRequest request) {
        return ok(departmentService.selectByCode(code));
    }
}
